﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.SqlClient;

using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.DataAccess.SqlDatabase;

using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.Domain.Commands;

namespace Fuse8.ContentManagementFramework.DataAccess.SqlAccess.Mappers
{
    internal class CmsTemplateDataMapper : BaseSqlEntityDataMapper<CmsTemplate, int>
    {
        private static BaseSqlEntityDataMapper<CmsTemplate, int> _based = new BaseSqlEntityDataMapper<CmsTemplate, int>(new string[] { "SiteGroup", "Site", "SiteCategory", "TemplateRegions", "TemplateRegionsCount" });

        private static Dictionary<string, Func<object, IList<SqlParameter>>> _mappersTo = new Dictionary<string, Func<object, IList<SqlParameter>>>();

        static CmsTemplateDataMapper()
        {
            _mappersTo.Add("cms_sp_TemplateSelectAll",
                (p) =>
                {
                    return _based.MapTo("cms_sp_TemplateSelectAll", p, false);
                });
            _mappersTo.Add("cms_sp_TemplateSelectOne",
                (p) =>
                {
                    return _based.MapTo("cms_sp_TemplateSelectOne", p, false);
                });
            _mappersTo.Add("cms_sp_TemplateAdd", CreateMapperForTemplateCreate);
            _mappersTo.Add("cms_sp_TemplateSave", CreateMapperForTemplateUpdate);
        }

        public CmsTemplateDataMapper()
            : base()
        { }

        public override IList<SqlParameter> MapTo(string sp, object parameter, bool isForCreate)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(parameter, "parameter");

            return _mappersTo.ContainsKey(sp) ?
                _mappersTo[sp](parameter) :
                base.MapTo(sp, parameter, isForCreate);
        }

        public override CmsTemplate MapFrom(string sp, SqlDataReader reader)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(reader, "reader");

            var result = new CmsTemplate
            {
                Id = reader.GetInt32(reader.GetOrdinal("TemplateId")),
                SiteId = !reader.IsDBNull(reader.GetOrdinal("SiteId")) ?
                    reader.GetInt32(reader.GetOrdinal("SiteId")) :
                    new Nullable<int>(),
                SiteGroupId = !reader.IsDBNull(reader.GetOrdinal("SiteGroupId")) ?
                    reader.GetInt32(reader.GetOrdinal("SiteGroupId")) :
                    new Nullable<int>(),
                TemplateName = reader.GetString(reader.GetOrdinal("TemplateName")),
                TemplateUrl = reader.GetString(reader.GetOrdinal("TemplateUrl")),
                TemplateTypeKey = reader.GetInt32(reader.GetOrdinal("TemplateTypeKey")),
                IsDefault = reader.GetBoolean(reader.GetOrdinal("IsDefault")),
                CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy")) ?
                    reader.GetInt32(reader.GetOrdinal("LastUpdatedBy")) :
                    new Nullable<int>(),
                DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated")) ?
                   reader.GetDateTime(reader.GetOrdinal("DateLastUpdated")) :
                   new Nullable<DateTime>(),
                TemplateRegionsCount = reader.GetInt32(reader.GetOrdinal("TemplateRegionsCount")),
                DefaultRegionId = !reader.IsDBNull(reader.GetOrdinal("DefaultRegionId")) ?
                    reader.GetInt32(reader.GetOrdinal("DefaultRegionId")) :
                    default(int?)
            };

            return result;
        }

        public override CmsTemplate MapFromMulti(string sp, SqlDataReader reader, CmsTemplate stepEntity, int index)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(reader, "reader");
            
            if (index == 0)
            {
                stepEntity = new CmsTemplate
                                 {
                                     Id = reader.GetInt32(reader.GetOrdinal("TemplateId")),
                                     SiteId = !reader.IsDBNull(reader.GetOrdinal("SiteId"))
                                                  ? reader.GetInt32(reader.GetOrdinal("SiteId"))
                                                  : new Nullable<int>(),
                                     SiteGroupId = !reader.IsDBNull(reader.GetOrdinal("SiteGroupId"))
                                                       ? reader.GetInt32(reader.GetOrdinal("SiteGroupId"))
                                                       : new Nullable<int>(),
                                     TemplateName = reader.GetString(reader.GetOrdinal("TemplateName")),
                                     TemplateUrl = reader.GetString(reader.GetOrdinal("TemplateUrl")),
                                     TemplateTypeKey = reader.GetInt32(reader.GetOrdinal("TemplateTypeKey")),
                                     IsDefault = reader.GetBoolean(reader.GetOrdinal("IsDefault")),
                                     CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                                     DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                                     LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy"))
                                                         ? reader.GetInt32(reader.GetOrdinal("LastUpdatedBy"))
                                                         : new Nullable<int>(),
                                     DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated"))
                                                           ? reader.GetDateTime(reader.GetOrdinal("DateLastUpdated"))
                                                           : new Nullable<DateTime>(),
                                     DefaultRegionId = !reader.IsDBNull(reader.GetOrdinal("DefaultRegionId"))
                                                           ? reader.GetInt32(reader.GetOrdinal("DefaultRegionId"))
                                                           : default(int?)
                                 };
            }
            else if (index == 1)
            {
                var stepTemplateRegion = new CmsTemplateRegion
                {
                    Id = reader.GetInt32(reader.GetOrdinal("TemplateRegionId")),
                    TemplateId = reader.GetInt32(reader.GetOrdinal("TemplateId")),
                    TemplateRegionName = reader.GetString(reader.GetOrdinal("TemplateRegionName"))
                };

                if (!stepEntity.HasRegions)
                {
                    stepEntity.TemplateRegions = new CmsTemplateRegion[] { stepTemplateRegion };
                }
                else
                {
                    stepEntity.TemplateRegions = 
                        stepEntity.TemplateRegions
                        .Concat(new CmsTemplateRegion[] { stepTemplateRegion })
                        .ToList();
                }
            }
            else
            {
                throw new InvalidOperationException(string.Format("Stored procedure {0} can't return more than {1} result", sp, index));
            }

            return stepEntity;
        }

        private static IList<SqlParameter> CreateMapperForTemplateCreate(object parameter)
        {
            //todo: refactor this
            IList<SqlParameter> result = new List<SqlParameter>();

            var cmsTemplate = parameter as CmsTemplate;
            if (cmsTemplate != null)
            {
                result.Add(new SqlParameter("@Id", cmsTemplate.Id) { Direction = ParameterDirection.ReturnValue });

                if (cmsTemplate.SiteId.HasValue)
                {
                    result.Add(new SqlParameter("SiteId", cmsTemplate.SiteId.Value));
                }
                if (cmsTemplate.SiteGroupId.HasValue)
                {
                    result.Add(new SqlParameter("SiteGroupId", cmsTemplate.SiteGroupId.Value));
                }

                result.Add(new SqlParameter("TemplateName", cmsTemplate.TemplateName));
                result.Add(new SqlParameter("TemplateUrl", cmsTemplate.TemplateUrl));
                result.Add(new SqlParameter("TemplateTypeKey", cmsTemplate.TemplateTypeKey));
                result.Add(new SqlParameter("IsDefault", cmsTemplate.IsDefault));
                result.Add(new SqlParameter("DefaultRegionId", cmsTemplate.DefaultRegionId));

                if (cmsTemplate.HasRegions)
                {
                    string delimiter = ";"; //TODO : move to settings

                    result.Add(new SqlParameter("TemplateRegions",
                        cmsTemplate.TemplateRegions
                            .Select(p => p.TemplateRegionName)
                            .Aggregate(
                                (working, next) =>
                                {
                                    return string.Format("{0}{1}{2}", working, delimiter, next);
                                })));
                    result.Add(new SqlParameter("TemplareRegionDelimiter", delimiter));
                }

                result.Add(new SqlParameter("CreatedBy", cmsTemplate.CreatedBy));
                result.Add(new SqlParameter("DateCreated", cmsTemplate.DateCreated));
            }

            return result;
        }

        private static IList<SqlParameter> CreateMapperForTemplateUpdate(object parameter)
        {
            IList<SqlParameter> result = new List<SqlParameter>();

            var cmsTemplate = parameter as CmsTemplate;
            if (cmsTemplate != null)
            {
                result.Add(new SqlParameter("TemplateId", cmsTemplate.Id));

                if (cmsTemplate.SiteId.HasValue)
                {
                    result.Add(new SqlParameter("SiteId", cmsTemplate.SiteId.Value));
                }
                if (cmsTemplate.SiteGroupId.HasValue)
                {
                    result.Add(new SqlParameter("SiteGroupId", cmsTemplate.SiteGroupId.Value));
                }

                if (cmsTemplate.HasRegions)
                {
                    string delimiter = ";"; //TO DO : move to settings

                    result.Add(new SqlParameter("TemplateRegions",
                        cmsTemplate.TemplateRegions
                            .Select(p => p.TemplateRegionName)
                            .Aggregate(
                                (working, next) =>
                                {
                                    return string.Format("{0}{1}{2}", working, delimiter, next);
                                })));
                    result.Add(new SqlParameter("TemplareRegionDelimiter", delimiter));
                }

                result.Add(new SqlParameter("TemplateName", cmsTemplate.TemplateName));
                result.Add(new SqlParameter("TemplateUrl", cmsTemplate.TemplateUrl));
                result.Add(new SqlParameter("TemplateTypeKey", cmsTemplate.TemplateTypeKey));
                result.Add(new SqlParameter("IsDefault", cmsTemplate.IsDefault));
                result.Add(new SqlParameter("DefaultRegionId", cmsTemplate.DefaultRegionId));

                result.Add(new SqlParameter("LastUpdatedBy", cmsTemplate.LastUpdatedBy));
                result.Add(new SqlParameter("DateLastUpdated", cmsTemplate.DateLastUpdated));
            }

            return result;
        }
    }
}
